-- nbody_dp.vhd
-- by Brittle 2009

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
-- synthesis translate_off
Library XilinxCoreLib;
use ieee.std_logic_textio.all;
library std;
use std.textio.all;
-- synthesis translate_on
LIBRARY work;
USE work.fpcore.ALL;

ENTITY nbody_dp IS
  PORT (
  clk  : in std_logic;
  sclr : in std_logic;
  ce   : in std_logic;
	accs : in std_logic_vector(2 downto 0); -- select accumulator inputs
  accr : in std_logic; -- register accumulator outputs
  pi_x : in std_logic_vector(31 downto 0);
  pi_y : in std_logic_vector(31 downto 0);
  pi_z : in std_logic_vector(31 downto 0);
  pj_x : in std_logic_vector(31 downto 0);
  pj_y : in std_logic_vector(31 downto 0);
  pj_z : in std_logic_vector(31 downto 0);
  pj_m : in std_logic_vector(31 downto 0);
  eps  : in std_logic_vector(31 downto 0);
  o_x  : out std_logic_vector(31 downto 0);
  o_y  : out std_logic_vector(31 downto 0);
  o_z  : out std_logic_vector(31 downto 0));
END nbody_dp;

ARCHITECTURE structural of nbody_dp IS

  COMPONENT reg IS
    GENERIC (
      w : positive := 32);
    PORT (
      clk  : IN  std_logic;
      ce   : IN  std_logic;
      d    : IN  std_logic_VECTOR(w-1 downto 0);
      q    : OUT std_logic_VECTOR(w-1 downto 0));
  END component;

  COMPONENT delay IS
    GENERIC (
      w : positive := 32;
      l : positive := 8);
    PORT (
      clk  : IN  std_logic;
      sclr : IN  std_logic;
      ce   : IN  std_logic;
      di   : IN  std_logic_VECTOR(w-1 downto 0);
      do   : OUT std_logic_VECTOR(w-1 downto 0));
  END component;

  signal FP_1          : std_logic_vector(31 downto 0);

  signal rx, ry, rz    : std_logic_vector(31 downto 0);
  signal rx_dly        : std_logic_vector(31 downto 0);
  signal ry_dly        : std_logic_vector(31 downto 0);
  signal rz_dly        : std_logic_vector(31 downto 0);
  signal rxx, ryy, rzz : std_logic_vector(31 downto 0);
  signal dd0, dd1, dd  : std_logic_vector(31 downto 0);
  signal dd_dly        : std_logic_vector(31 downto 0);
  signal d0, d1, d2, d : std_logic_vector(31 downto 0);
  signal s             : std_logic_vector(31 downto 0);
  signal pjm_dly       : std_logic_vector(31 downto 0);
  signal ax, ay, az    : std_logic_vector(31 downto 0);
  signal axs, ays, azs : std_logic_vector(31 downto 0);
  signal oxs, oys, ozs : std_logic_vector(31 downto 0);
  signal ox, oy, oz    : std_logic_vector(31 downto 0);
  signal x_reg, y_reg, z_reg    : std_logic_vector(31 downto 0);

BEGIN

  FP_1 <= X"3F800000";

  -- rx = p_j.x - p_i.x; ry = p_j.y - p_i.y; rz = p_j.z - p_i.z;
  U_rx:  fpsub_sp
         port map (clk=>clk, sclr=>sclr, ce=>ce, a=>pj_x, b=>pi_x, result=>rx);
  U_ry:  fpsub_sp
         port map (clk=>clk, sclr=>sclr, ce=>ce, a=>pj_y, b=>pi_y, result=>ry);
  U_rz:  fpsub_sp
         port map (clk=>clk, sclr=>sclr, ce=>ce, a=>pj_z, b=>pi_z, result=>rz);

  U_rxdly: delay generic map (w=>32, l=>112)
         port map (clk=>clk, sclr=>sclr, ce=>ce, di=>rx, do=>rx_dly);
  U_rydly: delay generic map (w=>32, l=>112)
         port map (clk=>clk, sclr=>sclr, ce=>ce, di=>ry, do=>ry_dly);
  U_rzdly: delay generic map (w=>32, l=>112)
         port map (clk=>clk, sclr=>sclr, ce=>ce, di=>rz, do=>rz_dly);

  -- rxx = rx^2; ryy = ry^2; rzz = rz^2;
  U_rxx: fpmul_sp
         port map (clk=>clk, sclr=>sclr, ce=>ce, a=>rx, b=>rx, result=>rxx);
  U_ryy: fpmul_sp
         port map (clk=>clk, sclr=>sclr, ce=>ce, a=>ry, b=>ry, result=>ryy);
  U_rzz: fpmul_sp
         port map (clk=>clk, sclr=>sclr, ce=>ce, a=>rz, b=>rz, result=>rzz);

  -- dd = rxx + ryy + rzz + EPS;
  U_dd0: fpadd_sp
         port map (clk=>clk, sclr=>sclr, ce=>ce, a=>rxx, b=>ryy, result=>dd0);
  U_dd1: fpadd_sp
         port map (clk=>clk, sclr=>sclr, ce=>ce, a=>rzz, b=>eps, result=>dd1);
  U_dd:  fpadd_sp
         port map (clk=>clk, sclr=>sclr, ce=>ce, a=>dd0, b=>dd1, result=>dd);

  -- d = 1 / sqrt(dd^3);
  U_d0:  fpmul_sp
         port map (clk=>clk, sclr=>sclr, ce=>ce, a=>dd, b=>dd, result=>d0);
  U_dmul_dly: delay generic map (w=>32, l=>8)
         port map (clk=>clk, sclr=>sclr, ce=>ce, di=>dd, do=>dd_dly);
  U_d1:  fpmul_sp
         port map (clk=>clk, sclr=>sclr, ce=>ce, a=>d0, b=>dd_dly, result=>d1);
  U_d2:  fpsqr_sp
         port map (clk=>clk, sclr=>sclr, ce=>ce, a=>d1, result=>d2);
  U_d:   fpdiv_sp
         port map (clk=>clk, sclr=>sclr, ce=>ce, a=>FP_1, b=>d2, result=>d);

  -- s = p_j.m * d;
	U_pjm_dly: delay generic map (w=>32, l=>116)
         port map (clk=>clk, sclr=>sclr, ce=>ce, di=>pj_m, do=>pjm_dly);
  U_s:   fpmul_sp
         port map (clk=>clk, sclr=>sclr, ce=>ce, a=>pjm_dly, b=>d, result=>s);

  -- ax = rx * s; ay = ry * s; az = rz * s;
  U_ax:  fpmul_sp
         port map (clk=>clk, sclr=>sclr, ce=>ce, a=>rx_dly, b=>s, result=>ax);
  U_ay:  fpmul_sp
         port map (clk=>clk, sclr=>sclr, ce=>ce, a=>ry_dly, b=>s, result=>ay);
  U_az:  fpmul_sp
         port map (clk=>clk, sclr=>sclr, ce=>ce, a=>rz_dly, b=>s, result=>az);

  -- ox += ax; oy += ay; oz += az;
  axs <= ax and (31 downto 0 => accs(0)) when accs(1) = '0' else x_reg;
  oxs <= ox and (31 downto 0 => accs(2));
  U_reg_x: reg
         port map (clk=>clk, ce=>accr, d=>ox, q=>x_reg);
  U_ox:  fpadd_sp
         port map (clk=>clk, sclr=>sclr, ce=>ce, a=>axs, b=>oxs, result=>ox);

  ays <= ay and (31 downto 0 => accs(0)) when accs(1) = '0' else y_reg;
  oys <= oy and (31 downto 0 => accs(2));
  U_reg_y: reg
         port map (clk=>clk, ce=>accr, d=>oy, q=>y_reg);
  U_oy:  fpadd_sp
         port map (clk=>clk, sclr=>sclr, ce=>ce, a=>ays, b=>oys, result=>oy);

  azs <= az and (31 downto 0 => accs(0)) when accs(1) = '0' else z_reg;
  ozs <= oz and (31 downto 0 => accs(2));
  U_reg_z: reg
         port map (clk=>clk, ce=>accr, d=>oz, q=>z_reg);
  U_oz:  fpadd_sp
         port map (clk=>clk, sclr=>sclr, ce=>ce, a=>azs, b=>ozs, result=>oz);

  o_x <= x_reg;
  o_y <= y_reg;
  o_z <= z_reg;

END structural;
